package com.xyhy.starter.mfx.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.constant.SqlOperator;
import com.mybatisflex.core.query.QueryColumn;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryTable;
import com.mybatisflex.core.query.QueryWrapper;
import com.xyhy.core.base.model.vo.TreeNodeVO;
import com.xyhy.core.utils.db.DBUtil;
import com.xyhy.core.web.annotation.QueryOperator;
import com.xyhy.starter.mfx.entity.MfxObject;
import com.xyhy.starter.mfx.entity.MfxType;

import java.util.*;

public class MfxUtil {

  public static <QO, TABLE extends QueryTable> QueryWrapper buildQuery(QO qo, TABLE table) {
    QueryWrapper query = QueryWrapper.create();

    Map<String, QueryColumn> columnMap = new HashMap<>();
    Arrays.asList(ReflectUtil.getFields(table.getClass())).forEach(x -> {
      Object fieldValue = ReflectUtil.getFieldValue(table, x.getName());
      if (fieldValue instanceof QueryColumn) {
        columnMap.put(x.getName(), (QueryColumn) fieldValue);
      }
    });

    Arrays.asList(ReflectUtil.getFields(qo.getClass())).forEach(x -> {
      Object qoFieldValue = ReflectUtil.getFieldValue(qo, x.getName());
      if (Objects.isNull(qoFieldValue)) return;

      QueryOperator operator = x.getAnnotation(QueryOperator.class);
      Boolean ignore = Optional.ofNullable(operator).map(y -> y.ignore()).orElse(false);
      SqlOperator sqlOperator = Optional.ofNullable(operator).map(y -> y.value()) //
              .map(y -> SqlOperator.valueOf(y.name())).orElse(SqlOperator.EQUALS);
      if (ignore) return;

      QueryColumn tableColumn = columnMap.get(StrUtil.toUnderlineCase(x.getName()).toUpperCase());
      if (Objects.isNull(tableColumn)) return;

      query.and(create(tableColumn, sqlOperator, qoFieldValue));
    });

    return query;
  }

  public static QueryCondition create(QueryColumn tableColumn, SqlOperator sqlOperator, Object qoFieldValue) {
    Object resultValue = qoFieldValue;
    sqlOperator = Optional.ofNullable(sqlOperator).orElse(SqlOperator.EQUALS);
    switch (sqlOperator) {
      case LIKE:
      case NOT_LIKE:
        resultValue = like(qoFieldValue.toString());
        break;
      case LIKE_LEFT:
      case NOT_LIKE_LEFT:
        resultValue = likeLeft(qoFieldValue.toString());
        break;
      case LIKE_RIGHT:
      case NOT_LIKE_RIGHT:
        resultValue = likeRight(qoFieldValue.toString());
        break;
      default:
        break;
    }

    return QueryCondition.create(tableColumn, sqlOperator, resultValue);
  }

  public static String like(String name) {
    return "%" + DBUtil.likeClear(name) + "%";
  }

  public static String likeLeft(String name) {
    return DBUtil.likeClear(name) + "%";
  }

  public static String likeRight(String name) {
    return "%" + DBUtil.likeClear(name);
  }

  public static <T extends MfxObject> TreeNodeVO<Long> buildTree(T t) {
    TreeNodeVO vo = BeanUtil.toBean(t, TreeNodeVO.class);
    vo.setLabel(t.getName());
    return vo;
  }

  public static <T extends MfxType> TreeNodeVO<String> buildTree(T t) {
    TreeNodeVO vo = BeanUtil.toBean(t, TreeNodeVO.class);
    vo.setLabel(t.getName());
    return vo;
  }

}
